import VueRouter from 'vue-router'
import UrlUtil from '../utils/url'
import ArrayUtil from '../utils/array'
import clone from 'clone'

const rootList = [], staticRouteList = []

let appName = null

const options = {
  /**
   * 设置根路由
   * @param {*} roots
   */
  setRoots (roots) {
    const map = {}
    rootList.map(root => {
      map[root.path] = root
    })
    roots.map(root => {
      root.path = `/${root.path.split('/').filter(str => str !== '').join('/')}`
      root.children = root.children || []
      if (map[root.path]) {
        console.warn(`[router] 路由被覆盖: ${root.path}`)
        rootList.splice(rootList.indexOf(map[root.path]), 1, root)
      } else {
        rootList.push(root)
      }
    })
  },
  /**
   * 注册静态路由
   * @param {*} routes
   */
  registStaticRoutes (routes) {
    routes.map(r => {
      this.addRoute(r)
      staticRouteList.push(r)
    })
  },
  /**
   * 注册子路由
   * @param {*} children  子路由配置信息
   * @param {*} root      根路由路径（可为根路由路径）
   * @param {*} statics   是否静态路由
   */
  registRootChildren (children, root) {
    !root && (root = '/')
    if (typeof (root) == 'string') {
      root = rootList.find(route => route.path == root)
    }
    !root && console.error(`[registRootChildren] 未找到根路由`)
    root.children = (root.children || []).concat(children)
  },
  /**
   * 注册动态路由
   * @param {*} children
   * @param {*} root
   */
  registDynamicRoutes (children, root) {
    !root && (root = '/')
    if (typeof (root) == 'string') {
      root = rootList.find(route => route.path == root || route.path == '/' || route.path == '')
    }
    !root && console.error(`[registRootChildren] 未找到根路由`)
    children.map(child => {
      child.meta.dynamic = true
    })
    root.children = (root.children || []).concat(children)
  },
  /**
   * 加载动态路由配置文件
   * @param {*} fileList
   * @param {*} key
   */
  loadRouteConfigFiles: (fileList, rootpath, key = 'pc') => { },
  /**
   * 扁平化路由
   * @param {*} routeConfig
   * @returns
   */
  getFlatRoutes (routeConfig) {
    const rootMap = {}, configures = clone(routeConfig)
    Object.keys(configures).map((rootpath, index) => {
      rootMap[rootpath] = rootMap[rootpath] || {}
      ArrayUtil.flat(configures[rootpath], 'children', index).map(route => {
        route.meta = route.meta || {}
        route.title = route.meta.title
        route.meta._parent = route._parent
        if (!route.path) {
          return
        }
        // path为绝对路径，则提升该节点到父节点同一级（从父节点的 children 中移除该节点）
        if (route.path.startsWith('/')) {
          // 从父节点中移除该节点
          route._parent?.children?.splice(route._parent?.children.indexOf(route), 1)
          // 标记为绝对路径
          route.meta.absolute = true
        }
        if (route.path.startsWith('http://') || route.path.startsWith('https://')) {
          route.meta.absolute = true
        } else if (!route.path.startsWith('/')) {
          // 补全相对路径
          const pathList = ArrayUtil.getParents(route).filter(p => p.path && !p.path.startsWith('https://') && !p.path.startsWith('http://')).map(p => p.path)
          route.path = `/${pathList.join('/')}/${route.path}`.replace(/\/\/+/g, '/')
        }
        rootMap[rootpath][route.path] = route
      })
    })
    return rootMap
  },
  getRouteConfig: () => { },
  getRootList () { return rootList },
  getRoot (rootpath) {
    const root = rootList.find(root => root.path == rootpath)
    if (root) {
      return root
    }
    console.error(`[getRoot] 找不到指定路由: ${rootpath}`)
  },
  /**
   * 前置路由守卫
   * @param {*} to
   * @param {*} from
   * @param {*} next
   */
  beforeEachFn (to, from, next) {
    this.setDocumentTitle(to)
    // to.query && (to.query.timestamp = new Date().getTime())
    this.onBeforeEach(to, from, next)
    let _to
    if (!to.query.currentAppList && from.query.currentAppList) {
      _to = { path: to.path, query: to.query, params: to.params, meta: to.meta }
      _to.path += `${_to.path.indexOf('?') !== -1 ? '&' : '?'}${'currentAppList=' + from.query.currentAppList}`
      _to.query.currentAppList = from.query.currentAppList
    }
    if (getNotNeedLoginPath().includes(to.path)) {
      next()
    } else if (!this.store.getLoginUser()) {
      this.onNeedLoginInfo().then(() => {
        // 用户信息初始化后，跳转下一个路由
        if (this.store.getLoginUser()) {
          nextRoute(_to ?? to, from, next)
        } else {
          console.error('未获取到登录用户信息')
        }
      }).catch(e => {
        const redirect = UrlUtil.getURLParam('redirect')
        this.redirectLogin(redirect)
      })
    } else {
      next(_to)
    }
  },
  setDocumentTitle (to) {
    !appName && (appName = this.store.getAppConfig('_appName', ''))
    const routeList = to.matched.concat()
    let meta = routeList.length == 0 ? {} : routeList.pop().meta
    while (meta.hidden) {
      meta = routeList.pop().meta
    }
    if (meta?.title) {
      document.title = meta.title + ' - ' + appName
    } else {
      document.title = appName || ''
    }
  },
  afterDynamicRoutesBuild () {
    return new Promise(resolve => {
      resolve()
    })
  },
  /**
   * 路由跳转
   */
  onBeforeEach (to, form, next) { },
  /**
   * 路由跳转完成
   */
  onAfterEach () { },
  /**
   * 默认打开链接
   * @param {*} url
   */
  open (url) {
    return new Promise((resolve) => {
      window.open(url)
      resolve()
    })
  }
}

function nextRoute (to, from, next) {
  // 请求带有 redirect 重定向时，登录自动重定向到该地址
  const redirect = decodeURIComponent(from.query.redirect || to.path)
  if (to.path === redirect) {
    next({ ...to, replace: true })
  } else {
    // 跳转到目标路由
    next({ path: redirect })
  }
}

function getNotNeedLoginPath () {
  return staticRouteList.map(r => {
    return r.path
  })
}

const originalPush = VueRouter.prototype.push
const originalReplace = VueRouter.prototype.replace
VueRouter.prototype.push = function (location, onResolve, onReject) {
  if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
  return originalPush.call(this, location).catch(err => err)
}
VueRouter.prototype.replace = function (location, onResolve, onReject) {
  if (onResolve || onReject) return originalReplace.call(this, location, onResolve, onReject)
  return originalReplace.call(this, location).catch(err => err)
}

export function Router (Vue, store) {
  Vue.use(VueRouter)

  const router = new VueRouter({
    base: process.env.BASE_URL || '/',
    mode: process.env.BASE_URL.startsWith('/') ? 'history' : 'hash',
    routes: [],
    scrollBehavior (to, from, savedPosition) {
      if (to.meta.keepAlive) {
        return savedPosition || to.meta.scroll || { x: 0, y: 0 }
      }
      return { x: 0, y: 0 }
    }
  })
  router.isHash = router.mode == 'hash'

  router.store = store

  Object.assign(router, options)

  router.beforeEach((to, from, next) => {
    router.beforeEachFn(to, from, next)
  })

  router.afterEach((to, from, next) => {
    router.onAfterEach(to, from, next)
  })
  return router
}